import React, { PureComponent } from 'react';
import Ellipsis from '@/components/Ellipsis';
import An from '@/components/An';
import { themeLight, themeDark, commonConfig, pieConfig, fitHeight } from '../config';
import styles from '../index.less';

const { defaultTheme } = commonConfig;
const {
  defaultTotalFontSize,
  defaultTitleFontSize,
  defaultTitleMarginTop,
  defaultTitleLines,
} = pieConfig;

class WaterWave extends PureComponent {
  state = {
    viewportScale: window.viewportScale,
  };

  componentDidMount() {
    this.renderChart();
    window.addEventListener(
      'resize',
      () => {
        requestAnimationFrame(() => this.resize());
      },
      { passive: true }
    );
  }

  componentDidUpdate(props) {
    const { percent } = this.props;
    if (props.percent !== percent) {
      // 不加这个会造成绘制缓慢
      // this.renderChart('update');
      this.renderChart();
    }
  }

  componentWillUnmount() {
    cancelAnimationFrame(this.timer);
    if (this.node) {
      this.node.innerHTML = '';
    }
    window.removeEventListener('resize', this.resize);
  }

  resize = () => {
    this.setState({ viewportScale: window.viewportScale });
  };

  renderChart(type) {
    const { theme = defaultTheme } = this.props;
    const { defaultColor } = theme === 'dark' ? themeDark : themeLight;
    const { percent = 0, color = defaultColor } = this.props;
    const data = percent / 100;
    const self = this;
    cancelAnimationFrame(this.timer);
    // data === undefined数据为0不出现图形处理
    if (!this.node || (data !== 0 && !data)) {
      return;
    }

    const canvas = this.node;
    const ctx = canvas.getContext('2d');
    const canvasWidth = canvas.width;
    const canvasHeight = canvas.height;
    const radius = canvasWidth / 2;
    const lineWidth = 2;
    const cR = radius - lineWidth;

    ctx.beginPath();
    ctx.lineWidth = lineWidth * 2;

    const axisLength = canvasWidth - lineWidth;
    const unit = axisLength / 8;
    const range = 0.2; // 振幅
    let currRange = range;
    const xOffset = lineWidth;
    let sp = 0; // 周期偏移量
    let currData = 0;
    const waveupsp = 0.005; // 水波上涨速度

    let arcStack = [];
    const bR = radius - lineWidth;
    const circleOffset = -(Math.PI / 2);
    let circleLock = true;

    for (let i = circleOffset; i < circleOffset + 2 * Math.PI; i += 1 / (8 * Math.PI)) {
      arcStack.push([radius + bR * Math.cos(i), radius + bR * Math.sin(i)]);
    }

    const cStartPoint = arcStack.shift();
    ctx.strokeStyle = color;
    ctx.moveTo(cStartPoint[0], cStartPoint[1]);

    function drawSin() {
      ctx.beginPath();
      ctx.save();

      const sinStack = [];
      for (let i = xOffset; i <= xOffset + axisLength; i += 20 / axisLength) {
        const x = sp + (xOffset + i) / unit;
        const y = Math.sin(x) * currRange;
        const dx = i;
        const dy = 2 * cR * (1 - currData) + (radius - cR) - unit * y;

        ctx.lineTo(dx, dy);
        sinStack.push([dx, dy]);
      }

      const startPoint = sinStack.shift();

      ctx.lineTo(xOffset + axisLength, canvasHeight);
      ctx.lineTo(xOffset, canvasHeight);
      ctx.lineTo(startPoint[0], startPoint[1]);

      const gradient = ctx.createLinearGradient(0, 0, 0, canvasHeight);
      gradient.addColorStop(0, theme === 'dark' ? color : '#ffffff');
      gradient.addColorStop(1, color);
      ctx.fillStyle = gradient;
      ctx.fill();
      ctx.restore();
    }

    function render() {
      ctx.clearRect(0, 0, canvasWidth, canvasHeight);
      if (circleLock && type !== 'update') {
        if (arcStack.length) {
          const temp = arcStack.shift();
          ctx.lineTo(temp[0], temp[1]);
          ctx.stroke();
        } else {
          circleLock = false;
          ctx.lineTo(cStartPoint[0], cStartPoint[1]);
          ctx.stroke();
          arcStack = null;

          ctx.globalCompositeOperation = 'destination-over';
          ctx.beginPath();
          ctx.lineWidth = lineWidth;
          ctx.arc(radius, radius, bR, 0, 2 * Math.PI, 1);

          ctx.beginPath();
          ctx.save();
          ctx.arc(radius, radius, radius - 3 * lineWidth, 0, 2 * Math.PI, 1);

          ctx.restore();
          ctx.clip();
          ctx.fillStyle = color;
        }
      } else {
        if (data >= 0.85) {
          if (currRange > range / 4) {
            const t = range * 0.01;
            currRange -= t;
          }
        } else if (data <= 0.1) {
          if (currRange < range * 1.5) {
            const t = range * 0.01;
            currRange += t;
          }
        } else {
          if (currRange <= range) {
            const t = range * 0.01;
            currRange += t;
          }
          if (currRange >= range) {
            const t = range * 0.01;
            currRange -= t;
          }
        }
        if (data - currData > 0) {
          currData += waveupsp;
        }
        if (data - currData < 0) {
          currData -= waveupsp;
        }

        sp += 0.07;
        drawSin();
      }
      self.timer = requestAnimationFrame(render);
    }

    render();
  }

  render() {
    const { viewportScale } = this.state;
    const { theme = defaultTheme, style = {} } = this.props;
    const { defaultTotalColor, defaultTitleColor } = theme === 'dark' ? themeDark : themeLight;
    const {
      height,
      percent = 0,
      padding = 10,
      totalColor = defaultTotalColor,
      totalFontSize = defaultTotalFontSize,
      an,
      anParams = {},
      showAn = false,
      title,
      titleColor = defaultTitleColor,
      titleFontSize = defaultTitleFontSize,
      titleLines = defaultTitleLines, // 限制标题行数，若无需限制传0
    } = this.props;

    return (
      <div
        style={{
          textAlign: 'center',
          fontSize: 0,
          ...style,
          position: 'relative',
          height:
            height * window.viewportScale +
            (title ? titleLines * 21 * viewportScale : 0) +
            (showAn ? 21 * viewportScale : 0),
        }}
      >
        <div
          className={styles.waterWave}
          ref={n => (this.root = n)}
          style={{ width: height * window.viewportScale, height: height * window.viewportScale }}
        >
          <div
            style={{
              width: height,
              height,
              overflow: 'hidden',
              padding,
              transformOrigin: 'center top',
              transform: `scale(${viewportScale})`,
              marginLeft: (-(1 - window.viewportScale) * height) / 2,
            }}
          >
            <canvas
              className={styles.waterWaveCanvasWrapper}
              ref={n => (this.node = n)}
              width={(height - padding * 2) * 2}
              height={(height - padding * 2) * 2}
            />
          </div>
          <div
            style={{ color: totalColor, fontSize: totalFontSize * window.viewportScale }}
            className={styles.text}
          >
            <span>{percent}%</span>
          </div>
        </div>
        <div
          style={{
            position: 'absolute',
            width: '100%',
            textAlign: 'center',
            top: height * window.viewportScale,
          }}
        >
          {showAn && <An num={an} block {...anParams} height={fitHeight(21)} />}
          {title && (
            <div
              style={{
                color: titleColor,
                fontSize: titleFontSize * viewportScale,
                marginTop: defaultTitleMarginTop,
                height: titleLines * fitHeight(21),
                lineHeight: `${fitHeight(21)}px`,
              }}
              className={styles.title}
            >
              <Ellipsis lines={titleLines} tooltip>
                {title}
              </Ellipsis>
            </div>
          )}
        </div>
      </div>
    );
  }
}

export default WaterWave;
